#include <lversion.h>
#if L_VERSION_MODULE_BV_TREE == 120118

#include "BoundingVolume.h"

#include <lmath.h>

using namespace llib;
using namespace llib::geom;
using namespace llib::math;

void BV_AABB::Update( const Vec3f& point )
{
    _min = _max = point;
    _max.x += EPS_F;  _max.y += EPS_F;  _max.z += EPS_F;
    _min.x -= EPS_F;  _min.y -= EPS_F;  _min.z -= EPS_F;
}

void BV_AABB::Update( const MeshFace& tri )
{
    _min = _max = tri.GetVertexRef(0);
    
    Vec3f p = tri.GetVertexRef(1);
    if(_max.x < p.x) _max.x = p.x; else if(_min.x > p.x) _min.x = p.x;
    if(_max.y < p.y) _max.y = p.y; else if(_min.y > p.y) _min.y = p.y;
    if(_max.z < p.z) _max.z = p.z; else if(_min.z > p.z) _min.z = p.z;

    p = tri.GetVertexRef(2);
    if(_max.x < p.x) _max.x = p.x; else if(_min.x > p.x) _min.x = p.x;
    if(_max.y < p.y) _max.y = p.y; else if(_min.y > p.y) _min.y = p.y;
    if(_max.z < p.z) _max.z = p.z; else if(_min.z > p.z) _min.z = p.z;

    _max.x += EPS_F;  _max.y += EPS_F;  _max.z += EPS_F;
    _min.x -= EPS_F;  _min.y -= EPS_F;  _min.z -= EPS_F;
}

BV_AABB BV_AABB::Merge( const BV_AABB& first, const BV_AABB& second )
{
    BV_AABB res(first);

    if(res._max.x < second._max.x) res._max.x = second._max.x;
    if(res._max.y < second._max.y) res._max.y = second._max.y;
    if(res._max.z < second._max.z) res._max.z = second._max.z;

    if(res._min.x > second._min.x) res._min.x = second._min.x;
    if(res._min.y > second._min.y) res._min.y = second._min.y;
    if(res._min.z > second._min.z) res._min.z = second._min.z;

    return res;
}

Boolean BV_AABB::Intersect( const BV_AABB& first, const BV_AABB& second )
{
    return !( first._min.x > second._max.x || first._max.x < second._min.x ||
              first._min.y > second._max.y || first._max.y < second._min.y ||
              first._min.z > second._max.z || first._max.z < second._min.z );
}

void BV_kDOP<8>::Update( const Vec3f& point )
{
    _max[0] = _min[0] =  point.x + point.y + point.z;
    _max[1] = _min[1] =  point.x + point.y - point.z;
    _max[2] = _min[2] =  point.x - point.y + point.z;
    _max[3] = _min[3] = -point.x + point.y + point.z;

    _max[0] += EPS_F;  _max[1] += EPS_F;  _max[2] += EPS_F;  _max[3] += EPS_F;
    _min[0] -= EPS_F;  _min[1] -= EPS_F;  _min[2] -= EPS_F;  _min[3] -= EPS_F;
}

void BV_kDOP<8>::Update( const MeshFace& tri )
{
    BV_kDOP<8> bv0(tri.GetVertexRef(0));
    BV_kDOP<8> bv1(tri.GetVertexRef(1));
    bv0 = Merge(bv0, bv1);
    bv1.Update(tri.GetVertexRef(2));
    *this = Merge(bv0, bv1);
}

BV_kDOP<8> BV_kDOP<8>::Merge( const BV_kDOP<8>& first, const BV_kDOP<8>& second )
{
    BV_kDOP<8> res(first);

    if(res._max[0] < second._max[0]) res._max[0] = second._max[0];
    if(res._max[1] < second._max[1]) res._max[1] = second._max[1];
    if(res._max[2] < second._max[2]) res._max[2] = second._max[2];
    if(res._max[3] < second._max[3]) res._max[3] = second._max[3];

    if(res._min[0] > second._min[0]) res._min[0] = second._min[0];
    if(res._min[1] > second._min[1]) res._min[1] = second._min[1];
    if(res._min[2] > second._min[2]) res._min[2] = second._min[2];
    if(res._min[3] > second._min[3]) res._min[3] = second._min[3];

    return res;
}

Boolean BV_kDOP<8>::Intersect( const BV_kDOP<8>& first, const BV_kDOP<8>& second )
{
    return !( first._min[0] > second._max[0] || first._max[0] < second._min[0] ||
              first._min[1] > second._max[1] || first._max[1] < second._min[1] ||
              first._min[2] > second._max[2] || first._max[2] < second._min[2] ||
              first._min[3] > second._max[3] || first._max[3] < second._min[3] );
}

void BV_kDOP<12>::Update( const Vec3f& point )
{
    _max[0] = _min[0] = point.x + point.y;
    _max[1] = _min[1] = point.x - point.y;
    _max[2] = _min[2] = point.x + point.z;
    _max[3] = _min[3] = point.x - point.z;
    _max[4] = _min[4] = point.y + point.z;
    _max[5] = _min[5] = point.y - point.z;

    _max[0] += EPS_F; _max[1] += EPS_F; _max[2] += EPS_F; _max[3] += EPS_F; _max[4] += EPS_F; _max[5] += EPS_F;
    _min[0] -= EPS_F; _min[1] -= EPS_F; _min[2] -= EPS_F; _min[3] -= EPS_F; _min[4] -= EPS_F; _min[5] -= EPS_F;
}

void BV_kDOP<12>::Update( const MeshFace& tri )
{
    BV_kDOP<12> bv0(tri.GetVertexRef(0));
    BV_kDOP<12> bv1(tri.GetVertexRef(1));
    bv0 = Merge(bv0, bv1);
    bv1.Update(tri.GetVertexRef(2));
    *this = Merge(bv0, bv1);
}

BV_kDOP<12> BV_kDOP<12>::Merge( const BV_kDOP<12>& first, const BV_kDOP<12>& second )
{
    BV_kDOP<12> res(first);

    if(res._max[0] < second._max[0]) res._max[0] = second._max[0];
    if(res._max[1] < second._max[1]) res._max[1] = second._max[1];
    if(res._max[2] < second._max[2]) res._max[2] = second._max[2];
    if(res._max[3] < second._max[3]) res._max[3] = second._max[3];
    if(res._max[4] < second._max[4]) res._max[4] = second._max[4];
    if(res._max[5] < second._max[5]) res._max[5] = second._max[5];

    if(res._min[0] > second._min[0]) res._min[0] = second._min[0];
    if(res._min[1] > second._min[1]) res._min[1] = second._min[1];
    if(res._min[2] > second._min[2]) res._min[2] = second._min[2];
    if(res._min[3] > second._min[3]) res._min[3] = second._min[3];
    if(res._min[4] > second._min[4]) res._min[4] = second._min[4];
    if(res._min[5] > second._min[5]) res._min[5] = second._min[5];

    return res;
}

Boolean BV_kDOP<12>::Intersect( const BV_kDOP<12>& first, const BV_kDOP<12>& second )
{
    return !( first._min[0] > second._max[0] || first._max[0] < second._min[0] ||
              first._min[1] > second._max[1] || first._max[1] < second._min[1] ||
              first._min[2] > second._max[2] || first._max[2] < second._min[2] ||
              first._min[3] > second._max[3] || first._max[3] < second._min[3] ||
              first._min[4] > second._max[4] || first._max[4] < second._min[4] ||
              first._min[5] > second._max[5] || first._max[5] < second._min[5] );
}

BV_kDOP<14> BV_kDOP<14>::Merge( const BV_kDOP<14>& first, const BV_kDOP<14>& second )
{
    return BV_kDOP<14>( BV_6DOP::Merge(first._dop6, second._dop6), BV_8DOP::Merge(first._dop8, second._dop8) ); 
}

Boolean BV_kDOP<14>::Intersect( const BV_kDOP<14>& first, const BV_kDOP<14>& second )
{
    return BV_6DOP::Intersect(first._dop6, second._dop6) && BV_8DOP::Intersect(first._dop8, second._dop8);
}

BV_kDOP<18> BV_kDOP<18>::Merge( const BV_kDOP<18>& first, const BV_kDOP<18>& second )
{
    return BV_kDOP<18>( BV_6DOP::Merge(first._dop6, second._dop6), BV_12DOP::Merge(first._dop12, second._dop12) );
}

Boolean BV_kDOP<18>::Intersect( const BV_kDOP<18>& first, const BV_kDOP<18>& second )
{
    return BV_6DOP::Intersect(first._dop6, second._dop6) && BV_12DOP::Intersect(first._dop12, second._dop12);
}

BV_kDOP<20> BV_kDOP<20>::Merge( const BV_kDOP<20>& first, const BV_kDOP<20>& second )
{
    return BV_kDOP<20>( BV_8DOP::Merge(first._dop8, second._dop8), BV_12DOP::Merge(first._dop12, second._dop12) );
}

Boolean BV_kDOP<20>::Intersect( const BV_kDOP<20>& first, const BV_kDOP<20>& second )
{
    return BV_8DOP::Intersect(first._dop8, second._dop8) && BV_12DOP::Intersect(first._dop12, second._dop12);
}

BV_kDOP<26> BV_kDOP<26>::Merge( const BV_kDOP<26>& first, const BV_kDOP<26>& second )
{
    return BV_kDOP<26>( BV_6DOP::Merge(first._dop6, second._dop6),
                        BV_8DOP::Merge(first._dop8, second._dop8),
                        BV_12DOP::Merge(first._dop12, second._dop12) );
}

Boolean BV_kDOP<26>::Intersect( const BV_kDOP<26>& first, const BV_kDOP<26>& second )
{
    return BV_6DOP::Intersect(first._dop6, second._dop6) &&
           BV_8DOP::Intersect(first._dop8, second._dop8) &&
           BV_12DOP::Intersect(first._dop12, second._dop12);
}

#endif
